/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * BeanFactory是Spring Bean容器的根接口，是bean容器的基本客户端视图。
 * <p>其他接口类似ListableBeanFactory和ConfigurableBeanFactory可以用于特定的用途。
 * <p>此接口由包含许多bean定义的对象实现，每个bean定义由String名称唯一标识。
 * <p>根据bean定义，工厂将返回包含对象的独立实例（Prototype设计模式），或者单例共享实例（Singleton设计模式的高级替代，其中实例是工厂作用域的单例）。
 * <p>将返回哪种类型的实例取决于bean工厂配置：API是相同的。
 * 从Spring 2.0开始，根据具体的应用程序上下文（例如Web环境中的“request”和“session”作用域），可以使用更多的作用域。
 * <p>这种方法的重点是BeanFactory是应用程序组件的中央注册表，并集中应用程序组件的配置（例如，不再需要单个对象读取属性文件）。
 * <p>请注意，通常最好依靠依赖注入（“推送”配置），通过setter或构造函数来配置应用程序对象，而不是像BeanFactory查找一样使用任何形式的“拉”配置。
 * Spring的依赖注入功能是使用这个BeanFactory接口及其子接口实现的。
 * <p>通常，BeanFactory将加载存储在配置源（例如XML文档）中的bean定义，并使用code org.springframework.beans包来配置bean。
 * 但是，实现类可以直接在Java代码中直接返回它创建的Java对象。对如何存储定义没有限制：LDAP，RDBMS，XML，属性文件等。鼓励实现类支持bean之间的引用（依赖注入）。
 * <p>与ListableBeanFactory中的方法相反，如果是HierarchicalBeanFactory，则此接口中的所有操作也将检查父工厂。
 * 如果在此工厂实例中找不到bean，则会询问直接父工厂。此工厂实例中的Bean应该覆盖任何父工厂中同名的Bean。
 * <p>
 * Bean工厂实现应尽可能支持标准bean生命周期接口。 完整的初始化方法及其标准顺序是：
 * <p>BeanNameAware.setBeanName()
 * <p>BeanClassLoaderAware.setBeanClassLoader()
 * <p>BeanFactoryAware.setBeanFactory()
 * <p>EnvironmentAware.setEnvironment()
 * <p>EmbeddedValueResolverAware.setEmbeddedValueResolver()
 * <p>ResourceLoaderAware.setResourceLoader()  仅适用于在应用程序上下文中运行时
 * <p>ApplicationEventPublisherAware.setApplicationEventPublisher() 仅适用于在应用程序上下文中运行时
 * <p>MessageSourceAware.setMessageSource() 仅适用于在应用程序上下文中运行时
 * <p>ApplicationContextAware.setApplicationContext() 仅适用于在应用程序上下文中运行时
 * <p>ServletContextAware.setServletContext() 仅适用于在应用程序上下文中运行时
 * <p>BeanPostProcessors.postProcessBeforeInitialization()和InitializingBean.afterPropertiesSet() 自定义初始化方法定义
 * <p>BeanPostProcessors.postProcessAfterInitialization()
 * <p>
 * 关闭bean工厂时，以下生命周期方法适用：
 * DestructionAwareBeanPostProcessors.postProcessBeforeDestruction()
 * DisposableBea.destroy 自定义的销毁方法定义
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 * @since 13 April 2001
 */
public interface BeanFactory {

	/**
	 * FactoryBean 的前缀，beanName 前加这个获取的就是FactoryBean 本身
	 */
	String FACTORY_BEAN_PREFIX = "&";


	/**
	 * 获取 beanName 对应的 bean 实例（可能涉及 bean 的创建）
	 * <p>1）会对别名进行转换
	 * <p>2）当前 BeanFactory 中找不到回去父级容器寻找
	 * <p>3）找不到就会创建
	 *
	 * @param name 1、name带有前缀 "&"，表示获取FactoryBean本身
	 *             <p>2、name不带有前缀 "&"，表示获取普通bean对象
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Behaves the same as {@link #getBean(String)}, but provides a measure of type
	 * safety by throwing a BeanNotOfRequiredTypeException if the bean is not of the
	 * required type. This means that ClassCastException can't be thrown on casting
	 * the result correctly, as can happen with {@link #getBean(String)}.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name         the name of the bean to retrieve
	 * @param requiredType type the bean must match; can be an interface or superclass
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException  if there is no such bean definition
	 * @throws BeanNotOfRequiredTypeException if the bean is not of the required type
	 * @throws BeansException                 if the bean could not be created
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Allows for specifying explicit constructor arguments / factory method arguments,
	 * overriding the specified default arguments (if any) in the bean definition.
	 *
	 * @param name the name of the bean to retrieve
	 * @param args arguments to use when creating a bean instance using explicit arguments
	 *             (only applied when creating a new instance as opposed to retrieving an existing one)
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException  if arguments have been given but
	 *                                       the affected bean isn't a prototype
	 * @throws BeansException                if the bean could not be created
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * Return the bean instance that uniquely matches the given object type, if any.
	 * <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
	 * but may also be translated into a conventional by-name lookup based on the name
	 * of the given type. For more extensive retrieval operations across sets of beans,
	 * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
	 *
	 * @param requiredType type the bean must match; can be an interface or superclass
	 * @return an instance of the single bean matching the required type
	 * @throws NoSuchBeanDefinitionException   if no bean of the given type was found
	 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
	 * @throws BeansException                  if the bean could not be created
	 * @see ListableBeanFactory
	 * @since 3.0
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Allows for specifying explicit constructor arguments / factory method arguments,
	 * overriding the specified default arguments (if any) in the bean definition.
	 * <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
	 * but may also be translated into a conventional by-name lookup based on the name
	 * of the given type. For more extensive retrieval operations across sets of beans,
	 * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
	 *
	 * @param requiredType type the bean must match; can be an interface or superclass
	 * @param args         arguments to use when creating a bean instance using explicit arguments
	 *                     (only applied when creating a new instance as opposed to retrieving an existing one)
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException  if arguments have been given but
	 *                                       the affected bean isn't a prototype
	 * @throws BeansException                if the bean could not be created
	 * @since 4.1
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/**
	 * Return a provider for the specified bean, allowing for lazy on-demand retrieval
	 * of instances, including availability and uniqueness options.
	 *
	 * @param requiredType type the bean must match; can be an interface or superclass
	 * @return a corresponding provider handle
	 * @see #getBeanProvider(ResolvableType)
	 * @since 5.1
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	/**
	 * Return a provider for the specified bean, allowing for lazy on-demand retrieval
	 * of instances, including availability and uniqueness options.
	 *
	 * @param requiredType type the bean must match; can be a generic type declaration.
	 *                     Note that collection types are not supported here, in contrast to reflective
	 *                     injection points. For programmatically retrieving a list of beans matching a
	 *                     specific type, specify the actual bean type as an argument here and subsequently
	 *                     use {@link ObjectProvider#orderedStream()} or its lazy streaming/iteration options.
	 * @return a corresponding provider handle
	 * @see ObjectProvider#iterator()
	 * @see ObjectProvider#stream()
	 * @see ObjectProvider#orderedStream()
	 * @since 5.1
	 */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	/**
	 * Does this bean factory contain a bean definition or externally registered singleton
	 * instance with the given name?
	 * <p>If the given name is an alias, it will be translated back to the corresponding
	 * canonical bean name.
	 * <p>If this factory is hierarchical, will ask any parent factory if the bean cannot
	 * be found in this factory instance.
	 * <p>If a bean definition or singleton instance matching the given name is found,
	 * this method will return {@code true} whether the named bean definition is concrete
	 * or abstract, lazy or eager, in scope or not. Therefore, note that a {@code true}
	 * return value from this method does not necessarily indicate that {@link #getBean}
	 * will be able to obtain an instance for the same name.
	 *
	 * @param name the name of the bean to query
	 * @return whether a bean with the given name is present
	 */
	boolean containsBean(String name);

	/**
	 * Is this bean a shared singleton? That is, will {@link #getBean} always
	 * return the same instance?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * independent instances. It indicates non-singleton instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isPrototype} operation to explicitly
	 * check for independent instances.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to query
	 * @return whether this bean corresponds to a singleton instance
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Is this bean a prototype? That is, will {@link #getBean} always return
	 * independent instances?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * a singleton object. It indicates non-independent instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isSingleton} operation to explicitly
	 * check for a shared singleton instance.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to query
	 * @return whether this bean will always deliver independent instances
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isSingleton
	 * @since 2.0.3
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given name
	 * would return an object that is assignable to the specified target type.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name        the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code ResolvableType})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #getType
	 * @since 4.2
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given name
	 * would return an object that is assignable to the specified target type.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name        the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code Class})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #getType
	 * @since 2.0.1
	 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 获取指定 name 的 bean 实例的类型，如果目标 bean 实例是一个 FactoryBean
	 * 则返回的使其创建实例的类型，即 FactoryBean#getObjectType
	 * 这会造成 FactoryBean 的提前实例化
	 * <p>1）支持别名解析
	 * <p>2）支持层级查找
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 返回指定 name 的所有别名，这意味这基于这些 name 获取的 bean 实例都是同一个
	 * 如果这个地方传入的是一个别名，那么会返回 bean 原始名称和别名组成的数组
	 * 支持层级查找
	 */
	String[] getAliases(String name);

}
